package com.example.demo.service.impl;

import com.example.demo.mapper.*;
import com.example.demo.model.dto.ActivityDTO;
import com.example.demo.model.dto.ActivityWithUserDTO;
import com.example.demo.model.entity.*;
import com.example.demo.model.enums.PrizeType;
import com.example.demo.model.enums.ResultCodeEnum;
import com.example.demo.model.request.activity.*;
import com.example.demo.model.response.*;
import com.example.demo.service.ActivityService;
import com.example.demo.util.*;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.text.ParseException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@Service
public class ActivityServiceImpl implements ActivityService {

    @Autowired
    GoodsMapper goodsMapper;

    @Autowired
    ActivityMapper activityMapper;

    @Autowired
    ActivityPrizeMapper activityPrizeMapper;

    @Autowired
    UserMapper userMapper;

    @Autowired
    PrizeRecordMapper prizeRecordMapper;

    @Autowired
    UserPrizeMapper userPrizeMapper;

    @Autowired
    CouponMapper couponMapper;

    @Autowired
    RedisMapper redisMapper;

    @Override
    public boolean create(CreateActivityRequest request) {
        //活动存在校验
        Activity existActivity = activityMapper.selectByName(request.getName());
        if (null != existActivity) {
            throw PromotionException.fail(ResultCodeEnum.ACTIVITY_NAME_EXISTED);
        }

        //时间校验
        Date startTime = null , endTime = null ;
        try {
            startTime = DateUtils.parseDate(request.getStartTime(), Constants.timeFormat);
            endTime = DateUtils.parseDate(request.getEndTime(), Constants.timeFormat);
        } catch (ParseException e) {
            e.printStackTrace();
            throw PromotionException.fail(ResultCodeEnum.TIME_PARSE_ERROR);
        }
        if (startTime.after(endTime)) {
            throw PromotionException.fail(ResultCodeEnum.START_TIME_AFTER_END_TIME);
        }

        List<Prize> prizeList = PrizeConverter.convert(request.getPrizeList());

        //统计中奖总概率
        Integer totalProbability = 0;
        //校验奖品
        for (Prize prize : prizeList) {
            //若奖品为实体商品，校验该商品是否已存在于商城中
            if (PrizeType.GOODS.getVal() == prize.getType()) {
                Goods goods = goodsMapper.selectById(prize.getGoodsId());
                if (null == goods) {
                    throw PromotionException.fail(ResultCodeEnum.GOODS_NOT_EXISTED);
                }
            }
            //中奖概率应为1-10000
            if (prize.getProbability() > 10000 || prize.getProbability() <= 0) {
                throw PromotionException.fail(ResultCodeEnum.PRIZE_PROBABILITY_INVALID);
            }
            totalProbability += prize.getProbability();
        }

        //总中奖概率应为1-10000
        if(totalProbability > 10000 || totalProbability <= 0) {
            throw PromotionException.fail(ResultCodeEnum.PRIZE_PROBABILITY_INVALID);
        }

        Activity activity = new Activity();
        activity.setName(request.getName());
        activity.setStartTime(startTime);
        activity.setEndTime(endTime);
        activity.setChance(request.getChance());
        //插入活动表
        activityMapper.insert(activity);
        int activityId = activity.getId();

        //插入活动奖品表
        for (Prize prize : prizeList) {
            prize.setActivityId(activityId);
            prize.setRemaining(prize.getNumber());
            activityPrizeMapper.insert(prize);
        }

        //插入redis
        redisMapper.setActivity(activityId);
        return true;
    }

    @Override
    public PageQueryActivityResponse pageQuery(PageInfo pageInfo) {
        PageQueryActivityResponse response = new PageQueryActivityResponse();

        //分页查询活动
        Integer offset = pageInfo.getPageSize() * (pageInfo.getCurrent() - 1);
        List<Activity> activityList = activityMapper.pageQuery(pageInfo.getPageSize(), offset);

        //查询每个活动的所有奖品
        List<ActivityDTO> activityDTOList = new ArrayList<>();
        for (Activity activity : activityList) {
            ActivityDTO activityDTO = new ActivityDTO();
            setActivity(activityDTO, activity);
            List<Prize> prizeList = activityPrizeMapper.selectByActivityId(activity.getId());
            for(Prize prize : prizeList) {
                if(PrizeType.GOODS.getVal() == prize.getType()) {
                    prize.setPrizeName(goodsMapper.selectById(prize.getGoodsId()).getName());
                } else if(PrizeType.COUPON.getVal() == prize.getType()) {
                    prize.setPrizeName(couponMapper.selectById(prize.getCouponId()).getName());
                }
            }
            activityDTO.setPrizeList(prizeList);
            activityDTOList.add(activityDTO);
        }
        response.setItems(activityDTOList);

        //查询总记录条数,并设置分页信息
        long totalItem = activityMapper.getCount();
        setPageInfo(response, totalItem, pageInfo.getCurrent(), pageInfo.getPageSize());
        return response;
    }

    @Override
    public boolean delete(Integer activityId) {
        Activity existActivity = activityMapper.selectById(activityId);
        if (null != existActivity) {
            activityMapper.delete(activityId);
            activityPrizeMapper.deleteActivity(activityId);
        }
        return true;
    }

    @Override
    public AttendActivityResponse attend(AttendActivityRequest request) {

        //查询用户id
        request.setUserId(userMapper.selectByUserName(request.getUserName()).getId());

        //用户与活动存在性校验
        User existUser = userMapper.selectById(request.getUserId());
        if (null == existUser) {
            throw PromotionException.fail(ResultCodeEnum.USER_NAME_NOT_EXISTED);
        }

        ActivityDTO existActivityDTO = redisMapper.getActivity(request.getActivityId());
        Activity existActivity ;
        if(existActivityDTO != null) {
            existActivity = convertToActivity(existActivityDTO);
        } else {
            existActivity = activityMapper.selectById(request.getActivityId());
            redisMapper.setActivity(request.getActivityId());
        }

        if (null == existActivity) {
            throw PromotionException.fail(ResultCodeEnum.ACTIVITY_NOT_EXISTED);
        }

        //活动时间校验
        Date date = new Date();
        if (date.before(existActivity.getStartTime())) {
            throw PromotionException.fail(ResultCodeEnum.ACTIVITY_NOT_START);
        }
        if (date.after(existActivity.getEndTime())) {
            throw PromotionException.fail(ResultCodeEnum.ACTIVITY_HAS_END);
        }

        //抽奖次数校验
        int drawCounts = prizeRecordMapper.getUserCount(request.getUserId(), request.getActivityId());
        if (drawCounts >= existActivity.getChance()) {
            throw PromotionException.fail(ResultCodeEnum.DRAW_CHANCE_NOT_ENOUGH);
        }

        //选奖
        List<Prize> prizeList;
        if(existActivityDTO != null) {
            prizeList = existActivityDTO.getPrizeList();
        } else {
            prizeList = activityPrizeMapper.selectByActivityId(request.getActivityId());
        }

        Prize hitPrize = DrawUtil.draw(prizeList);

        //未抽中或库存为0，都视为未中奖
        if (hitPrize == null || hitPrize.getRemaining() == 0) {
            //若未中奖，不扣库存，但要落库，记录抽奖
            Integer hitPrizeLevel = hitPrize == null ? null : hitPrize.getLevel();
            prizeRecordMapper.insert(buildPrizeRecord(existActivity.getId(), hitPrizeLevel, request.getUserId(), false));
            throw PromotionException.fail(ResultCodeEnum.PRIZE_NOT_HIT);
        }

        //设置奖品名称
        if(PrizeType.GOODS.getVal() == hitPrize.getType()) {
            hitPrize.setPrizeName(goodsMapper.selectById(hitPrize.getGoodsId()).getName());
        } else if (PrizeType.COUPON.getVal() == hitPrize.getType()) {
            hitPrize.setPrizeName(couponMapper.selectById(hitPrize.getCouponId()).getName());
        }

        //扣库存
        hitPrize.setRemaining(hitPrize.getRemaining() - 1);
        activityPrizeMapper.update(hitPrize);

        //落库
        prizeRecordMapper.insert(buildPrizeRecord(existActivity.getId(), hitPrize.getLevel(), request.getUserId(), true));
        userPrizeMapper.insert(buildUserPrize(hitPrize, request.getUserId(), request.getActivityId()));

        //构建response
        return buildAttendActivityResponse(hitPrize, request.getUserId());
    }

    private Activity convertToActivity(ActivityDTO activityDTO) {
        Activity activity = new Activity();
        activity.setId(activityDTO.getId());
        activity.setName(activityDTO.getName());
        Date startTime = null, endTime = null;
        try{
            startTime = DateUtils.parseDate(activityDTO.getStartTime(), Constants.timeFormat);
            endTime = DateUtils.parseDate(activityDTO.getEndTime(), Constants.timeFormat);
        } catch (ParseException e) {
            e.printStackTrace();
            throw PromotionException.fail(ResultCodeEnum.TIME_PARSE_ERROR);
        }
        activity.setStartTime(startTime);
        activity.setEndTime(endTime);
        activity.setChance(activityDTO.getChance());
        return activity;
    }



    @Override
    public QueryActivityRecordResponse queryRecord(QueryActivityRecordRequest request) {
        List<PrizeRecord> recordList = prizeRecordMapper.selectByActivityId(request.getActivityId());
        //移除未中奖记录
        recordList.removeIf(record -> record.getHit() == false);
        //查询中奖用户名称
        for(PrizeRecord record : recordList) {
            User user = userMapper.selectById(record.getUserId());
            record.setUserName(user.getUserName());
        }
        QueryActivityRecordResponse response = new QueryActivityRecordResponse();
        response.setItems(recordList);
        return response;
    }

    @Override
    public QueryUserPrizeResponse queryUserPrize(QueryUserPrizeRequest request) {
        //查询用户id
        request.setUserId(userMapper.selectByUserName(request.getUserName()).getId());
        //查询奖品
        List<UserPrize> userPrizeList = userPrizeMapper.selectByUserId(request.getUserId());
        QueryUserPrizeResponse response = new QueryUserPrizeResponse();
        response.setItems(userPrizeList);
        return response;
    }

    @Override
    public Boolean update(UpdateActivityRequest request) {
        //活动时间校验
        Date now = new Date();
        Date startTime = null , endTime = null ;
        try {
            startTime = DateUtils.parseDate(request.getStartTime(), Constants.timeFormat);
            endTime = DateUtils.parseDate(request.getEndTime(), Constants.timeFormat);
        } catch (ParseException e) {
            e.printStackTrace();
            throw PromotionException.fail(ResultCodeEnum.TIME_PARSE_ERROR);
        }

        //活动已开始，不允许修改
        if(startTime.before(now)) {
            throw PromotionException.fail(ResultCodeEnum.ACTIVITY_HAS_STARTED);
        }

        //开始时间晚于结束时间
        if (startTime.after(endTime)) {
            throw PromotionException.fail(ResultCodeEnum.START_TIME_AFTER_END_TIME);
        }

        Activity activity = buildActivity(request, startTime, endTime);

        //数据变更
        activityMapper.update(activity);
        return null;
    }

    @Override
    public ActivityDTO query(Integer id) {
        Activity existActivity = activityMapper.selectById(id);
        if (null == existActivity) {
            throw PromotionException.fail(ResultCodeEnum.ACTIVITY_NOT_EXISTED);
        }
        ActivityDTO activityDTO = new ActivityDTO();
        activityDTO.setId(existActivity.getId());
        activityDTO.setName(existActivity.getName());
        activityDTO.setStartTime(DateFormatUtils.format(existActivity.getStartTime(), Constants.timeFormat));
        activityDTO.setEndTime(DateFormatUtils.format(existActivity.getEndTime(), Constants.timeFormat));
        activityDTO.setChance(existActivity.getChance());
        return activityDTO;
    }

    @Override
    public PageQueryActivityByUserResponse pageQueryByUser(PageQueryActivityByUserRequest request) {
        PageQueryActivityByUserResponse response = new PageQueryActivityByUserResponse();

        //分页查询活动
        Integer offset = request.getPageSize() * (request.getCurrent() - 1);
        List<Activity> activityList = activityMapper.pageQuery(request.getPageSize(), offset);

        //查询每个活动的所有奖品
        List<ActivityWithUserDTO> activityWithUserDTOS = new ArrayList<>();
        for (Activity activity : activityList) {
            ActivityWithUserDTO activityWithUserDTO = new ActivityWithUserDTO();
            User user = userMapper.selectByUserName(request.getUserName());
            setActivity(activityWithUserDTO, activity, user.getId());
            List<Prize> prizeList = activityPrizeMapper.selectByActivityId(activity.getId());
            for(Prize prize : prizeList) {
                if(PrizeType.GOODS.getVal() == prize.getType()) {
                    prize.setPrizeName(goodsMapper.selectById(prize.getGoodsId()).getName());
                } else if(PrizeType.COUPON.getVal() == prize.getType()) {
                    prize.setPrizeName(couponMapper.selectById(prize.getCouponId()).getName());
                }
            }
            activityWithUserDTO.setPrizeList(prizeList);
            activityWithUserDTOS.add(activityWithUserDTO);
        }
        response.setItems(activityWithUserDTOS);

        //查询总记录条数,并设置分页信息
        long totalItem = activityMapper.getCount();
        setPageInfo(response, totalItem, request.getCurrent(), request.getPageSize());
        return response;
    }

    private Activity buildActivity(UpdateActivityRequest request, Date startTime, Date endTime) {
        Activity activity = new Activity();
        activity.setId(request.getId());
        activity.setName(request.getName());
        activity.setStartTime(startTime);
        activity.setEndTime(endTime);
        activity.setChance(request.getChance());
        return activity;
    }
    private AttendActivityResponse buildAttendActivityResponse(Prize prize, Integer userId) {
        AttendActivityResponse response = new AttendActivityResponse();
        response.setActivityId(prize.getActivityId());
        response.setPrizeLevel(prize.getLevel());
        response.setPrizeType(prize.getType());
        response.setGoodsId(prize.getGoodsId());
        response.setCouponId(prize.getCouponId());
        response.setUserId(userId);
        response.setPrizeName(prize.getPrizeName());
        return response;
    }

    private PrizeRecord buildPrizeRecord(Integer activityId, Integer prizeLevel, Integer userId, Boolean isHit) {
        PrizeRecord prizeRecord = new PrizeRecord();
        prizeRecord.setActivityId(activityId);
        prizeRecord.setPrizeLevel(prizeLevel);
        prizeRecord.setUserId(userId);
        prizeRecord.setHit(isHit);
        return prizeRecord;
    }

    private UserPrize buildUserPrize(Prize prize, Integer userId, Integer activityId) {
        UserPrize userPrize = new UserPrize();
        userPrize.setUserId(userId);
        userPrize.setPrizeType(prize.getType());
        userPrize.setPrizeName(prize.getPrizeName());
        if (PrizeType.COUPON.getVal() == userPrize.getPrizeType()) {
            userPrize.setPrizeId(prize.getCouponId());
        } else if (PrizeType.GOODS.getVal() == userPrize.getPrizeType()) {
            userPrize.setPrizeId(prize.getGoodsId());
        }
        userPrize.setValid(true);
        userPrize.setActivityName(activityMapper.selectById(activityId).getName());
        return userPrize;
    }

    /**
     * 设置activityWithUserDTO的活动信息
     *
     * @param activityWithUserDTO
     * @param activity
     */
    private void setActivity(ActivityWithUserDTO activityWithUserDTO, Activity activity, Integer userId) {
        activityWithUserDTO.setId(activity.getId());
        activityWithUserDTO.setName(activity.getName());
        activityWithUserDTO.setStartTime(DateFormatUtils.format(activity.getStartTime(), Constants.timeFormat));
        activityWithUserDTO.setEndTime(DateFormatUtils.format(activity.getEndTime(), Constants.timeFormat));
        activityWithUserDTO.setChance(activity.getChance());
        int drawCounts = prizeRecordMapper.getUserCount(userId, activity.getId());
        activityWithUserDTO.setRemainedChance(activity.getChance() - drawCounts);
    }

    /**
     * 设置activityDTO的活动信息
     *
     * @param activityDTO
     * @param activity
     */
    private void setActivity(ActivityDTO activityDTO, Activity activity) {
        activityDTO.setId(activity.getId());
        activityDTO.setName(activity.getName());
        activityDTO.setStartTime(DateFormatUtils.format(activity.getStartTime(), Constants.timeFormat));
        activityDTO.setEndTime(DateFormatUtils.format(activity.getEndTime(), Constants.timeFormat));
        activityDTO.setChance(activity.getChance());
    }

    /**
     * 设置response的分页信息
     *
     * @param response
     * @param totalItem
     * @param current
     * @param pageSize
     */
    private void setPageInfo(PageQueryActivityResponse response, long totalItem, int current, int pageSize) {
        response.setTotal(totalItem);
        response.setCurrent(current);
        response.setPageSize(pageSize);
        response.setTotalPage(PageUtil.calculateTotalPage(totalItem, pageSize));
    }

    /**
     * 设置response的分页信息
     *
     * @param response
     * @param totalItem
     * @param current
     * @param pageSize
     */
    private void setPageInfo(PageQueryActivityByUserResponse response, long totalItem, int current, int pageSize) {
        response.setTotal(totalItem);
        response.setCurrent(current);
        response.setPageSize(pageSize);
        response.setTotalPage(PageUtil.calculateTotalPage(totalItem, pageSize));
    }
}
